package com.jt.config;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.LinkedHashMap;

import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.defaults.DefaultSqlSessionFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.Scope;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import com.alibaba.druid.pool.DruidDataSource;
import com.jt.sys.service.realm.ShiroUserRealm;




/*
 * 整合mybatis
 */
//@Configuration
//这里配置扫描，在加载该类的时候，就会扫描指定包下的类，来创建对象
@EnableTransactionManagement//启用事务管理
@EnableAspectJAutoProxy
@ComponentScan(value = "com.jt", excludeFilters = {//excludeFilters不包含，排除的意思
@Filter(type = FilterType.ANNOTATION, classes = { Controller.class }) })
@PropertySource("classpath:configs.properties") // 表示这是一个类路径下的文件,shiro有自己内置的.properties文件，当shiro扫描到自己的时候，就不会扫描我们写的
public class AppRootConfig {
	public AppRootConfig() {
		System.out.println("AppRootConfig()");
	}
	
	
	@Bean(value = "sqlSessionTemplate")
	public SqlSessionTemplate newsqlSessionTemplate(SqlSessionFactory sqlSessionFactory){
		return new SqlSessionTemplate(sqlSessionFactory);
	}
	

	@Bean // 启用此对象可以加载多个properties文件
	public PropertySourcesPlaceholderConfigurer newPropertySourcesPlaceholderConfigurer() {
		return new PropertySourcesPlaceholderConfigurer();
	}

	
	
	
	// 配置druid
	@Scope("singleton")
	@Bean(value = "dataSource", initMethod = "init", destroyMethod = "close")
	public DruidDataSource newDataSource(@Value("${jdbcDriver}") String driver, @Value("${jdbcUrl}") String url
	// 基于注解从properties里面获取数据的时候用@Value("${jdbcDriver}"
			, @Value("${jdbcUser}") String user, @Value("${jdbcPassword}") String password) {
		DruidDataSource ds = new DruidDataSource();
		/*
		 * ds.setDriverClassName("com.mysql.jdbc.Driver");
		 * ds.setUrl("jdbc:mysql:///jtsys"); ds.setUsername("root");
		 * ds.setPassword("");
		 */
		ds.setDriverClassName(driver);
		ds.setUrl(url);
		ds.setUsername(user);
		ds.setPassword(password);
		return ds;
	}

	// 配置sqlsessionfactoryBean
	@Bean("sqlSessionFactory")
	public SqlSessionFactoryBean newSqlSessionFactory(DataSource dataSource) throws IOException {
		SqlSessionFactoryBean ssf = new SqlSessionFactoryBean();
		ssf.setDataSource(dataSource);
		String path = "classpath:mapper/sys/*.xml";
		// Resource[] resource={new ClassPathResource(path)};
		Resource[] resource = new PathMatchingResourcePatternResolver().getResources(path);
		ssf.setMapperLocations(resource);
		return ssf;
	}

	// 配置MapperScanner
	@Bean
	public MapperScannerConfigurer newScanner() {
		MapperScannerConfigurer ms = new MapperScannerConfigurer();
		ms.setBasePackage("com.jt.**.dao");
		ms.setSqlSessionFactoryBeanName("sqlSessionFactory");// 只有一个setSqlSessionFactoryBean时，这一行可以不写
		return ms;
	}

	
	
	
	
	// ---------------shiro----------------------
	
	
	@Bean("securityManager")
	public DefaultWebSecurityManager newDefaultWebSecurityManager(ShiroUserRealm userRealm) {//这里需要一个ShiroUserRealm类型的对象。
		DefaultWebSecurityManager sManager = new DefaultWebSecurityManager();
		sManager.setRealm(userRealm);
		return sManager;
	}

	/**
	 * 配置shiroFilterBean对象，
	 * 
	 * @param securityManager
	 * @return
	 */
	/*
	 * shiroFilter这个名字要和AppWebInitializer类下的onStartup方法中的dy.setInitParameter(
	 * "targetBeanName", "shiroFilter")里面的名字相同
	 */
	@Bean("shiroFilter") // 过滤器名字
	public ShiroFilterFactoryBean newShiroFilterFactoryBean(SecurityManager securityManager) {
		ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
		bean.setSecurityManager(securityManager);
		//当此用户是一个非认证的用户，需要先登录进行认证
		bean.setLoginUrl("/doLoginUI.do");
		LinkedHashMap<String, String> fcMap = new LinkedHashMap<>();
		// linkedhasmap是有序的，因为web.xml文件中的很多配置都是有序的，比如拦截器，谁在上面谁先起作用
		// 设置访问权限，以下这些内容可以写到配置文件或者数据库中
		fcMap.put("/bower_components/**", "anon");// anon表示允许匿名访问
		fcMap.put("/build/**", "anon");// anon表示允许匿名访问
		fcMap.put("/dist/**", "anon");// anon表示允许匿名访问
		fcMap.put("/plugins/**", "anon");// anon表示允许匿名访问
		fcMap.put("/doLogin.do", "anon");// anon表示允许匿名访问
		fcMap.put("/doLogout.do", "logout");// logout，会调用Subject的logout方法,此方法会将session清空，
		fcMap.put("/**", "authc");//剩余其他路径，这句话必须放在最下面，必须认证通过才可以访问
		bean.setFilterChainDefinitionMap(fcMap);

		return bean;
	}

	/**
	 * 配置声明周期管理器
	 * 
	 * @return
	 */
	@Bean("lifecycleBeanPostProcessor")
	public LifecycleBeanPostProcessor newLifecycleBeanPostProcessor() {
		return new LifecycleBeanPostProcessor();
	}

	/**
	 * 配置shiro授权
	 * @return
	 */
	@DependsOn(value = "lifecycleBeanPostProcessor")
	@Bean
	public DefaultAdvisorAutoProxyCreator newDefaultAdvisorAutoProxyCreator() {

		return new DefaultAdvisorAutoProxyCreator();
	}

	
	@Bean
	public AuthorizationAttributeSourceAdvisor newAuthorizationAttributeSourceAdvisor(SecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor bean = new AuthorizationAttributeSourceAdvisor();
		bean.setSecurityManager(securityManager);
		return bean;
	}

	//===========================transaction=======================
	//配置事务管理者对象
	@Bean("txManager")
	public DataSourceTransactionManager newDataSourceTransactionManager(DataSource dataSource){
		DataSourceTransactionManager tManager=new DataSourceTransactionManager();
		tManager.setDataSource(dataSource);
		return tManager;
	}
}
